/* Copyright (c) [2025] [zhi1208@126.com]
 * SPDX-License-Identifier: MIT
 */

/*********************
 *      INCLUDES
 *********************/
#include "lvgl.h"
#include "hmi_pg_def.h"
#include "hmi_anim.h"
#include "hmi_top_bar.h"
#include "hmi_png.h"
#include "hmi_tinyttf.h"
#include "hmi_subjects.h"
#include "hmi_hal.h"

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/
typedef struct
{
    int32_t target_width;
    int32_t target_height;
} btn_user_data_t;

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void create();
static void del();
static void enter_anim(lv_anim_completed_cb_t cb, uint32_t delay);
static uint32_t exit_anim(lv_anim_completed_cb_t cb, hmi_pg_t *enter_pg);

static lv_obj_t *btn_create(lv_obj_t *parent,
                            const char *name,
                            lv_color_t bg_color,
                            lv_event_cb_t cb,
                            lv_subject_t *subj);
static void btn_generic_ev_cb(lv_event_t *e);

static void led_strip_sw_ev_cb(lv_event_t *e);
static void normal_mode_ev_cb(lv_event_t *e);
static void color_mode_ev_cb(lv_event_t *e);
static void rainbow_mode_ev_cb(lv_event_t *e);

static void brightness_ctrl_create(lv_obj_t *parent);
static void color_ctrl_create(lv_obj_t *parent);
static void color_slider_event_cb(lv_event_t *e);

/**********************
 *  STATIC VARIABLES
 **********************/
static hmi_pg_t led_strip = {
    .name = "灯带",
    .bg_color = 0xff9a00,
    .del_on_pop = 1,
    .create = create,
    .del = del,
    .enter_anim = enter_anim,
    .exit_anim = exit_anim};

static lv_font_t *def_font_18;
static lv_font_t *def_font_16;
static lv_font_t *def_font_14;

static lv_color_t *canvas_buffer;

/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/
hmi_pg_t *hmi_pg_led_strip()
{
    return &led_strip;
}

/**********************
 *   STATIC FUNCTIONS
 **********************/
static void create()
{
    led_strip.root = lv_obj_create(NULL);
    lv_obj_remove_style_all(led_strip.root);
    lv_obj_set_style_pad_bottom(led_strip.root, 10, 0);
    lv_obj_set_flex_flow(led_strip.root, LV_FLEX_FLOW_COLUMN);
    lv_obj_set_flex_align(led_strip.root, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START);

    hmi_top_bar_create(led_strip.root, led_strip.name);

    lv_obj_t *cont = lv_obj_create(led_strip.root);
    lv_obj_remove_style_all(cont);
    lv_obj_set_flex_grow(cont, 1);
    lv_obj_set_width(cont, lv_pct(94));
    lv_obj_set_style_border_width(cont, 0, 0);

    static int32_t col_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
    static int32_t row_dsc[] = {LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_FR(1), LV_GRID_TEMPLATE_LAST};
    lv_obj_set_grid_dsc_array(cont, col_dsc, row_dsc);
    lv_obj_set_grid_align(cont, LV_GRID_ALIGN_SPACE_EVENLY, LV_GRID_ALIGN_SPACE_EVENLY);

    lv_obj_t *led_strip_cont = lv_obj_create(cont);
    lv_obj_set_size(led_strip_cont, lv_pct(66), lv_pct(66));
    lv_obj_set_style_border_width(led_strip_cont, 0, 0);
    lv_obj_set_style_bg_color(led_strip_cont, lv_color_hex(0xffedb2), 0);
    lv_obj_set_style_pad_all(led_strip_cont, 0, 0);
    lv_obj_set_flex_flow(led_strip_cont, LV_FLEX_FLOW_COLUMN);
    lv_obj_set_flex_align(led_strip_cont, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);

    brightness_ctrl_create(led_strip_cont);
    color_ctrl_create(led_strip_cont);

    lv_obj_t *switch_btn = btn_create(cont,
                                      "开关",
                                      lv_color_hex(0xffbf87),
                                      led_strip_sw_ev_cb,
                                      &hmi_led_strip_sw_subj);
    lv_obj_t *icon = lv_obj_get_child(switch_btn, 0);
    lv_image_set_src(icon, hmi_png("lightbulb_slash"));
    lv_obj_set_style_recolor_opa(icon, LV_OPA_COVER, 0);
    lv_obj_set_style_recolor(icon, lv_color_black(), 0);

    lv_obj_t *normal_mode = btn_create(cont,
                                       "普通",
                                       lv_color_hex(0xff9867),
                                       normal_mode_ev_cb,
                                       &hmi_led_strip_normal_subj);
    lv_obj_t *color_mode = btn_create(cont,
                                      "彩色",
                                      lv_color_hex(0xffbf87),
                                      color_mode_ev_cb,
                                      &hmi_led_strip_color_subj);
    lv_obj_t *rainbow_mode = btn_create(cont,
                                        "彩虹",
                                        lv_color_hex(0xff9867),
                                        rainbow_mode_ev_cb,
                                        &hmi_led_strip_rainbow_subj);
    lv_obj_t *blank = btn_create(cont,
                                 "空",
                                 lv_color_hex(0xff4545),
                                 NULL,
                                 NULL);

    lv_obj_set_grid_cell(led_strip_cont, LV_GRID_ALIGN_START, 0, 2, LV_GRID_ALIGN_CENTER, 0, 2);
    lv_obj_set_grid_cell(switch_btn, LV_GRID_ALIGN_START, 2, 1, LV_GRID_ALIGN_CENTER, 0, 1);
    lv_obj_set_grid_cell(normal_mode, LV_GRID_ALIGN_START, 2, 1, LV_GRID_ALIGN_CENTER, 1, 1);
    lv_obj_set_grid_cell(color_mode, LV_GRID_ALIGN_START, 0, 1, LV_GRID_ALIGN_CENTER, 2, 1);
    lv_obj_set_grid_cell(rainbow_mode, LV_GRID_ALIGN_START, 1, 1, LV_GRID_ALIGN_CENTER, 2, 1);
    lv_obj_set_grid_cell(blank, LV_GRID_ALIGN_START, 2, 1, LV_GRID_ALIGN_CENTER, 2, 1);
}
static void del()
{
    lv_obj_delete_async(led_strip.root);
    led_strip.root = NULL;

    if (def_font_16)
    {
        hmi_tiny_ttf_del(def_font_16);
        def_font_16 = NULL;
    }

    if (def_font_18)
    {
        hmi_tiny_ttf_del(def_font_18);
        def_font_18 = NULL;
    }

    if (canvas_buffer)
    {
        lv_free(canvas_buffer);
        canvas_buffer = NULL;
    }
}
static void enter_anim(lv_anim_completed_cb_t cb, uint32_t delay)
{
    hmi_enter_anim_default(led_strip.root, cb, delay);
}
static uint32_t exit_anim(lv_anim_completed_cb_t cb, hmi_pg_t *enter_pg)
{
    return hmi_exit_anim_default(led_strip.root, cb, enter_pg);
}

static lv_obj_t *btn_create(lv_obj_t *parent,
                            const char *name,
                            lv_color_t bg_color,
                            lv_event_cb_t cb,
                            lv_subject_t *subj)
{
    lv_obj_t *btn = lv_obj_create(parent);
    lv_obj_set_size(btn, lv_pct(33), lv_pct(33));
    lv_obj_set_style_border_width(btn, 0, 0);
    lv_obj_set_style_bg_color(btn, bg_color, 0);

    lv_obj_t *icon = lv_image_create(btn);
    lv_image_set_src(icon, hmi_png("satellite_map"));
    lv_obj_center(icon);

    if (!def_font_16)
        def_font_16 = hmi_tiny_ttf_create_static("def_font", 16, false);

    lv_obj_t *title = lv_label_create(btn);
    lv_obj_set_style_text_font(title, def_font_16, 0);
    lv_obj_align(title, LV_ALIGN_BOTTOM_MID, 0, 0);
    lv_label_set_text(title, name);

    lv_obj_t *indicator = lv_obj_create(btn);
    lv_obj_set_size(indicator, 30, 5);
    lv_obj_set_style_pad_all(indicator, 0, 0);
    lv_obj_set_style_bg_opa(indicator, LV_OPA_60, 0);
    lv_obj_set_style_bg_opa(indicator, LV_OPA_COVER, LV_STATE_CHECKED);
    lv_obj_set_style_bg_color(indicator, lv_palette_lighten(LV_PALETTE_GREY, 2), 0);
    lv_obj_set_style_bg_color(indicator, lv_palette_main(LV_PALETTE_BLUE), LV_STATE_CHECKED);
    lv_obj_set_style_shadow_width(indicator, 10, LV_STATE_CHECKED);
    lv_obj_set_style_shadow_color(indicator, lv_palette_main(LV_PALETTE_BLUE), LV_STATE_CHECKED);
    lv_obj_set_style_border_width(indicator, 0, 0);
    lv_obj_align(indicator, LV_ALIGN_TOP_MID, 0, 0);
    lv_obj_add_flag(indicator, LV_OBJ_FLAG_CHECKABLE);
    lv_obj_remove_flag(indicator, LV_OBJ_FLAG_CLICKABLE);

    lv_obj_update_layout(btn);
    btn_user_data_t *user_data = lv_malloc(sizeof(btn_user_data_t));
    user_data->target_width = lv_obj_get_width(btn);
    user_data->target_height = lv_obj_get_height(btn);
    lv_obj_add_event_cb(btn, btn_generic_ev_cb, LV_EVENT_ALL, user_data);

    if (cb)
        lv_obj_add_event_cb(btn, cb, LV_EVENT_CLICKED, NULL);

    if (subj)
        lv_obj_bind_state_if_eq(indicator, subj, LV_STATE_CHECKED, 1);

    return btn;
}

static void btn_generic_ev_cb(lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t *obj = lv_event_get_current_target_obj(e);
    btn_user_data_t *user_data = lv_event_get_user_data(e);

    if (code == LV_EVENT_PRESSED)
    {
        lv_anim_t a;
        lv_anim_init(&a);
        lv_anim_set_duration(&a, 100);
        lv_anim_set_var(&a, obj);
        lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_width);
        lv_anim_set_values(&a, lv_obj_get_width(obj), user_data->target_width - 10);
        lv_anim_start(&a);

        lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_height);
        lv_anim_set_values(&a, lv_obj_get_height(obj), user_data->target_height - 10);
        lv_anim_start(&a);
    }
    else if (code == LV_EVENT_PRESS_LOST || code == LV_EVENT_RELEASED)
    {
        lv_anim_t a;
        lv_anim_init(&a);
        lv_anim_set_duration(&a, 100);
        lv_anim_set_var(&a, obj);
        lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_width);
        lv_anim_set_values(&a, lv_obj_get_width(obj), user_data->target_width);
        lv_anim_start(&a);

        lv_anim_set_exec_cb(&a, (lv_anim_exec_xcb_t)lv_obj_set_height);
        lv_anim_set_values(&a, lv_obj_get_height(obj), user_data->target_height);
        lv_anim_start(&a);
    }
    else if (code == LV_EVENT_DELETE)
    {
        if (user_data)
            lv_free(user_data);
    }
}

static void led_strip_sw_ev_cb(lv_event_t *e)
{
    lv_subject_set_int(&hmi_led_strip_sw_subj, !lv_subject_get_int(&hmi_led_strip_sw_subj));
}

static void normal_mode_ev_cb(lv_event_t *e)
{
    lv_subject_set_int(&hmi_led_strip_normal_subj, 1);
    lv_subject_set_int(&hmi_led_strip_color_subj, 0);
    lv_subject_set_int(&hmi_led_strip_rainbow_subj, 0);
}

static void color_mode_ev_cb(lv_event_t *e)
{
    lv_subject_set_int(&hmi_led_strip_normal_subj, 0);
    lv_subject_set_int(&hmi_led_strip_color_subj, 1);
    lv_subject_set_int(&hmi_led_strip_rainbow_subj, 0);
}

static void rainbow_mode_ev_cb(lv_event_t *e)
{
    lv_subject_set_int(&hmi_led_strip_normal_subj, 0);
    lv_subject_set_int(&hmi_led_strip_color_subj, 0);
    lv_subject_set_int(&hmi_led_strip_rainbow_subj, 1);
}

static void brightness_ctrl_create(lv_obj_t *parent)
{
    if (!def_font_18)
        def_font_18 = hmi_tiny_ttf_create_static("def_font", 18, false);

    if (!def_font_14)
        def_font_14 = hmi_tiny_ttf_create_static("def_font", 14, false);

    lv_obj_t *brightness = lv_obj_create(parent);
    lv_obj_remove_style_all(brightness);
    lv_obj_set_size(brightness, lv_pct(100), lv_pct(40));

    lv_obj_t *brightness_slider = lv_slider_create(brightness);
    lv_obj_set_size(brightness_slider, lv_pct(80), lv_pct(40));
    lv_obj_set_style_bg_opa(brightness_slider, LV_OPA_COVER, 0);
    lv_obj_set_style_bg_color(brightness_slider, lv_palette_lighten(LV_PALETTE_GREY, 3), 0);
    lv_obj_set_style_bg_color(brightness_slider, lv_color_white(), LV_PART_INDICATOR);
    lv_obj_set_style_bg_grad_color(brightness_slider, lv_color_hex(0xffd460), LV_PART_INDICATOR);
    lv_obj_set_style_bg_grad_dir(brightness_slider, LV_GRAD_DIR_HOR, LV_PART_INDICATOR);
    lv_obj_set_style_border_color(brightness_slider, lv_color_white(), 0);
    lv_obj_set_style_border_width(brightness_slider, 2, 0);
    lv_obj_set_style_border_color(brightness_slider, lv_color_white(), LV_PART_INDICATOR);
    lv_obj_set_style_border_width(brightness_slider, 2, LV_PART_INDICATOR);
    lv_obj_set_style_radius(brightness_slider, 10, 0);
    lv_obj_set_style_radius(brightness_slider, 10, LV_PART_INDICATOR);
    lv_obj_set_style_bg_opa(brightness_slider, LV_OPA_TRANSP, LV_PART_KNOB);
    lv_obj_set_style_recolor_opa(brightness_slider, LV_OPA_30, LV_STATE_DISABLED);
    lv_obj_set_style_recolor(brightness_slider, lv_palette_main(LV_PALETTE_GREY), LV_STATE_DISABLED);
    lv_obj_align(brightness_slider, LV_ALIGN_BOTTOM_MID, 0, -10);
    lv_slider_set_range(brightness_slider, 0, 100);
    lv_obj_bind_state_if_eq(brightness_slider, &hmi_led_strip_sw_subj, LV_STATE_DISABLED, 0);

    lv_obj_t *brightness_label = lv_label_create(brightness);
    lv_obj_set_style_text_font(brightness_label, def_font_18, 0);
    lv_obj_align_to(brightness_label, brightness_slider, LV_ALIGN_OUT_TOP_LEFT, 0, -10);
    lv_label_set_text(brightness_label, "亮度");

    lv_obj_t *brightness_val = lv_label_create(brightness);
    lv_obj_set_style_text_font(brightness_val, def_font_14, 0);
    lv_obj_align_to(brightness_val, brightness_slider, LV_ALIGN_LEFT_MID, 10, 0);

    lv_slider_bind_value(brightness_slider, &hmi_led_strip_brightness_subj);
    lv_label_bind_text(brightness_val, &hmi_led_strip_brightness_subj, "%d");
}

static void color_ctrl_create(lv_obj_t *parent)
{
    lv_obj_t *color = lv_obj_create(parent);
    lv_obj_remove_style_all(color);
    lv_obj_set_size(color, lv_pct(100), lv_pct(40));
    lv_obj_bind_flag_if_eq(color, &hmi_led_strip_color_subj, LV_OBJ_FLAG_HIDDEN, 0);

    lv_obj_t *color_band = lv_obj_create(color);
    lv_obj_remove_style_all(color_band);
    lv_obj_set_size(color_band, lv_pct(80), lv_pct(40));
    lv_obj_set_style_radius(color_band, 10, 0);
    lv_obj_set_style_clip_corner(color_band, true, 0);
    lv_obj_set_style_recolor_opa(color_band, LV_OPA_30, LV_STATE_DISABLED);
    lv_obj_set_style_recolor(color_band, lv_palette_main(LV_PALETTE_GREY), LV_STATE_DISABLED);
    lv_obj_align(color_band, LV_ALIGN_BOTTOM_MID, 0, -10);
    lv_obj_bind_state_if_eq(color_band, &hmi_led_strip_sw_subj, LV_STATE_DISABLED, 0);

    lv_obj_update_layout(color);
    int32_t canvas_width = lv_obj_get_width(color) * 0.8;
    int32_t canvas_height = lv_obj_get_height(color) * 0.4;

    canvas_buffer = lv_malloc(canvas_width * canvas_height * sizeof(lv_color_t));
    lv_obj_t *canvas = lv_canvas_create(color_band);
    lv_canvas_set_buffer(canvas, canvas_buffer, canvas_width, canvas_height, LV_COLOR_FORMAT_NATIVE);
    lv_obj_center(canvas);

    for (int32_t x = 0; x < canvas_width; x++)
    {
        uint16_t hue = (x * 360) / canvas_width;
        lv_color_t color = lv_color_hsv_to_rgb(hue, 100, 100);

        for (int y = 0; y < canvas_height; y++)
            lv_canvas_set_px(canvas, x, y, color, LV_OPA_COVER);
    }

    lv_obj_t *color_slider = lv_slider_create(color);
    lv_obj_set_size(color_slider, lv_pct(80), lv_pct(40));
    lv_obj_set_style_bg_opa(color_slider, LV_OPA_TRANSP, 0);
    lv_obj_set_style_bg_opa(color_slider, LV_OPA_TRANSP, LV_PART_INDICATOR);
    lv_obj_set_style_radius(color_slider, 10, 0);
    lv_obj_set_style_radius(color_slider, 10, LV_PART_INDICATOR);
    lv_obj_set_style_pad_all(color_slider, -3, LV_PART_KNOB);
    lv_obj_set_style_radius(color_slider, LV_RADIUS_CIRCLE, LV_PART_KNOB);
    lv_obj_set_style_border_width(color_slider, 3, LV_PART_KNOB);
    lv_obj_set_style_border_color(color_slider, lv_color_white(), LV_PART_KNOB);
    lv_obj_set_style_bg_opa(color_slider, LV_OPA_COVER, LV_PART_KNOB);
    lv_obj_set_style_recolor_opa(color_slider, LV_OPA_30, LV_STATE_DISABLED);
    lv_obj_set_style_recolor(color_slider, lv_palette_main(LV_PALETTE_GREY), LV_STATE_DISABLED);
    lv_obj_align(color_slider, LV_ALIGN_BOTTOM_MID, 0, -10);
    lv_slider_set_range(color_slider, 0, 360);
    lv_obj_add_event_cb(color_slider, color_slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
    lv_obj_bind_state_if_eq(color_slider, &hmi_led_strip_sw_subj, LV_STATE_DISABLED, 0);

    lv_obj_t *color_label = lv_label_create(color);
    lv_obj_set_style_text_font(color_label, def_font_18, 0);
    lv_obj_align_to(color_label, color_slider, LV_ALIGN_OUT_TOP_LEFT, 0, -10);
    lv_label_set_text(color_label, "颜色");

    lv_slider_bind_value(color_slider, &hmi_led_strip_hue_subj);
    lv_obj_send_event(color_slider, LV_EVENT_VALUE_CHANGED, NULL);
}

static void color_slider_event_cb(lv_event_t *e)
{
    lv_obj_t *slider = lv_event_get_target(e);

    int32_t val = lv_slider_get_value(slider);
    lv_obj_set_style_bg_color(slider, lv_color_hsv_to_rgb(val, 100, 100), LV_PART_KNOB);
}
